﻿using System;
using System.Collections.Generic;
using System.Configuration;
using Tau.DataAccess;
using Tau.Model;
using System.Linq;
using System.Linq.Expressions;
using Tau.ViewModels;

namespace Tau.Service
{
    public partial class TauService
    {
        public Page AddPage(Page page)
        {
            //set parent to the "non displayed" paretn
            page.ParentPageId = 291;

            //set visibility to true
            page.IsDisplayedToPublic = true;

            if (ConfigurationManager.AppSettings["IsDevDeployment"].ToLower() == "true")
            {
                page.PageCode = FixPageCodeForDev(page.PageCode);
            }
             
            //map model to db object
            var adapter = new Adapters.Page();
            tblPage dbObject = adapter.GetDbObject(page);

            //perform the add
            _context.tblPages.AddObject(dbObject);
            _context.SaveChanges();

            //return model
            return adapter.GetModelObject(dbObject);
        }

        public Page AddParentPage(Page parentPage)
        {
            //set visibility to true
            parentPage.IsDisplayedToPublic = true;

            //map model to db object
            var adapter = new Adapters.Page();
            tblPage dbObject = adapter.GetDbObject(parentPage);

            //perform the add
            _context.tblPages.AddObject(dbObject);
            _context.SaveChanges();

            //return model
            return adapter.GetModelObject(dbObject);
        }

        private string FixPageCodeForDev(string pageCode)
        {
            return pageCode.Replace("img src=\"Image", "img src=\"http://www.vesuviuspress.com/dev/Image");
        }

        public void UpdatePage(Page page)
        {
            if (page.PageCode != null && ConfigurationManager.AppSettings["IsDevDeployment"].ToLower() == "true")
            {
                page.PageCode = FixPageCodeForDev(page.PageCode);
            }

            //get existing page 
            tblPage dbPage = _context.tblPages.SingleOrDefault(p => p.pageID == page.PageId);

            dbPage.pageCode = page.PageCode;
            dbPage.pageName = page.PageName;
            dbPage.pageTitle = page.PageTitle;
            dbPage.orderID = page.OrderId;
         
            //get the existing page dbObject
            _context.SaveChanges();
        }

        public List<Page> GetAllPages()
        {
            List<tblPage> dbPageList = _context.tblPages.OrderBy(p => p.orderID).ToList();

            List<Page> returnPages = new Adapters.Page().GetModelList(dbPageList);
            
            foreach (var page in returnPages)
            {
                if (page.PageName == null || page.PageName.ToLower() != "not displayed")
                {
                    page.HasChildren = dbPageList.Exists(p => p.parentPageID == page.PageId);
                }
                else
                {
                    page.HasChildren = true;
                }
            }

            return returnPages;
        }

        public List<Page> GetPublicPages()
        {
            var returnPages = new List<Page>();

            var pages = GetAllPages().Where(page => page.IsDisplayedToPublic).ToList();

            var parentPages = pages.FindAll(page => page.ParentPageId == 0);

            //Add parent page and all siblings in order
            foreach(var parentPage in parentPages)
            {
                returnPages.Add(parentPage);
                var siblingPages = pages.FindAll(page => page.ParentPageId == parentPage.PageId);
                returnPages.AddRange(siblingPages);
            }

            return returnPages;
        }

        public Page GetPage(int pageId)
        {
            tblPage page = _context.tblPages.SingleOrDefault(p => p.pageID == pageId);
            return new Adapters.Page().GetModelObject(page);
        }

        public void DeletePage(int pageId)
        {
            tblPage pageToDelete = _context.tblPages.SingleOrDefault(p => p.pageID == pageId);

            _context.tblPages.DeleteObject(pageToDelete);
            _context.SaveChanges();
        }

        public PageList GetSortedPageList(string sortBy, bool sortDescending)
        {
            IQueryable<Page> pageQuery = new Adapters.Page().GetModelList(_context.tblPages.ToList()).AsQueryable();

            var param = Expression.Parameter(typeof(Page), "page");
            var sortExpression = Expression.Lambda<Func<Page, object>>(Expression.Convert(Expression.Property(param, sortBy), typeof(object)), param);
            IQueryable<Page> sortedPages = null;

            if (sortDescending)
            {
                sortedPages = pageQuery.OrderByDescending(sortExpression);
            }
            else
            {
                sortedPages = pageQuery.OrderBy(sortExpression);
            }

            return new PageList()
                        {
                            Pages =sortedPages.ToList(),
                            SortBy = sortBy,
                            SortDescending = sortDescending
                        };
        }

        private int GetNextTopOrderId()
        {
            int? topOrderId = _context.tblPages.OrderByDescending(p => p.topOrderID).First().topOrderID;
            if (topOrderId.HasValue)
            {
                return topOrderId.Value + 1;
            }
            return 1;
        }

        private int GetNextOrderId()
        {
            int? orderId = _context.tblPages.OrderByDescending(p => p.orderID).First().orderID;
            if (orderId.HasValue)
            {
                return orderId.Value + 1;
            }
            return 1;
        }

        private void DecrementOrderId(int greaterThan)
        {
            var pagesToUpdate = _context.tblPages.Where(p => p.orderID > greaterThan);
            foreach (var pageInDb in pagesToUpdate)
            {
                pageInDb.orderID = pageInDb.orderID - 1;
            }
        }

        private void DecrementTopOrderId(int topNavId, int greaterThan)
        {
            var pagesToUpdate = _context.tblPages.Where(p => p.topNavID == topNavId && p.topOrderID > greaterThan);
            foreach (var pageInDb in pagesToUpdate)
            {
                pageInDb.topOrderID = pageInDb.topOrderID - 1;
            }
        }

        public void UpdatePageHierarchy(int parentPageId, List<int> childPageIds)
        {
            tblPage pageToEdit = null;

            var order = 0;
            foreach(var pageId in childPageIds)
            {
                pageToEdit = _context.tblPages.SingleOrDefault(p => p.pageID == pageId);
                pageToEdit.parentPageID = parentPageId;
                pageToEdit.orderID = order;
                order++;
            }
            _context.SaveChanges();
        }


        public void UpdatePageOrder(int pageId, int pageOrder)
        {
            Page pageToUpdate = GetPage(pageId);
            pageToUpdate.OrderId = pageOrder;
            UpdatePage(pageToUpdate);
        }
    }
}
